//////////////////////////////////////////////////////////////////////
//   MQ2TribSave by somelamedruid
//
//   v1.0 2-5-07 Basic inactivity monitoring (player and mouse locs) and switching off tribute
//
//   usage - /tribsave <minutes> -- this will tell the program If im inactive for at list this
//  many minutes when my timer is about to expire, switch off tribute to avoid wasting trib
//	Lasy Modibyed By: A_Enchanter_00

#include "../MQ2Plugin.h"

PreSetup("MQ2TribSave");
PLUGIN_VERSION(8.1010);

#define TRIB_OFF_TIME 10000

bool bTribStatus = false;					// Trib Save Status

bool bCheckMouse = false;					// Trib Check Move
int iOldMouseX,iOldMouseY;

bool bCheckMove = false;					// Trib Check Move
float fOldLocX,fOldLocY;

bool bCheckCasting = true;					// Trib Check Casting
bool bCheckCastingDetrimental = false;		// Trib Check Casting Detrimental only

bool bCheckAttacking = true;				// Trib Check Attacking
bool bCheckGotHit = false;					// Trib Check Got Hit

char cTribCombatZones[MAX_STRING] = {0};	// Trib Combat Zones
char cTribNoCombatZones[MAX_STRING] = {0};	// Trib NoCombat Zones
bool bTribAutoActive = false;				// Trib Auto Mode
int iTribIdelTime = 5;

bool bOneShotOff,bOneShotOn = false;

char cPowerSource[MAX_STRING];				// Power source
int iPowerSourceSeconds;					// Power source Seconds
int iPowerSourceSlot;						// Power source Slot

time_t lastActive = time(NULL);

char Buffer[MAX_STRING];					// Buffer for String manipulatsion

bool ReadWindowINI(bool announceLoading = false);
VOID WriteWindowINI();

VOID setAction() {
	iOldMouseX = ((PMOUSEINFO)EQADDR_MOUSE)->X;
	iOldMouseY = ((PMOUSEINFO)EQADDR_MOUSE)->Y;
	fOldLocX = GetCharInfo()->pSpawn->X;
	fOldLocY = GetCharInfo()->pSpawn->Y;
	lastActive = time(NULL);
}

bool isCastingSpell() {
	if( bCheckCastingDetrimental ) {
		if ( PSPELL pSpell = (PSPELL)GetSpellByID(GetCharInfo()->pSpawn->CastingData.SpellID) ) {
			if ( pSpell->SpellType == 0 ) return true;
		}
	} else if ( GetCharInfo()->pSpawn->CastingData.SpellID != -1 ) return true;
	return false;
}

VOID status(bool fullStatus = false) {
	WriteChatf("[MQ2TribSave]:: Idel time \ag%d\ax min, Power Source Idel time \ag%d\ax sec.", iTribIdelTime, iPowerSourceSeconds);	
	if( fullStatus ) {
		WriteChatf("[MQ2TribSave]:: Saving[%s] Mouse[%s] Move[%s] Casting[%s] Attacking[%s] Auto[%s]", bTribStatus?"\agON\ax":"\arOFF\ax", bCheckMouse?"\agON\ax":"\arOFF\ax", bCheckMove?"\agON\ax":"\arOFF\ax", bCheckCasting?"\agON\ax":"\arOFF\ax", bCheckAttacking?"\agON\ax":"\arOFF\ax", bTribAutoActive?"\agON\ax":"\arOFF\ax");
		WriteChatf("[MQ2TribSave]:: Combat Zones: %s", cTribCombatZones);
		WriteChatf("[MQ2TribSave]:: No Combat Zones: %s", cTribNoCombatZones);
	}
}

bool combatZone() {
    if ( !ppWorldData || !pWorldData ) return false;

	if( !stricmp(((PWORLDDATA)pWorldData)->ZoneArray[GetCharInfo()->zoneId]->ShortName,"PoKnowledge") ||
		!stricmp(((PWORLDDATA)pWorldData)->ZoneArray[GetCharInfo()->zoneId]->ShortName,"PoTranquility") ||
		!stricmp(((PWORLDDATA)pWorldData)->ZoneArray[GetCharInfo()->zoneId]->ShortName,"GuildLobby") ||
		!stricmp(((PWORLDDATA)pWorldData)->ZoneArray[GetCharInfo()->zoneId]->ShortName,"GuildHall") ||
		!stricmp(((PWORLDDATA)pWorldData)->ZoneArray[GetCharInfo()->zoneId]->ShortName,"Nexus") ||
		!stricmp(((PWORLDDATA)pWorldData)->ZoneArray[GetCharInfo()->zoneId]->ShortName,"Potimea") ||
		!stricmp(((PWORLDDATA)pWorldData)->ZoneArray[GetCharInfo()->zoneId]->ShortName,"Bazaar") ) {
		return false;
	}

	sprintf(Buffer,"|%s|",((PWORLDDATA)pWorldData)->ZoneArray[GetCharInfo()->zoneId]->ShortName);
	strlwr(Buffer);

	char szTemp[MAX_STRING]={0};

	if( cTribNoCombatZones[1] ) {
		strcpy(szTemp,cTribNoCombatZones);
		strlwr(szTemp);
		if( strstr(szTemp,Buffer) ) return false;
	}
	if( cTribCombatZones[1] ) {
		strcpy(szTemp,cTribCombatZones);
		strlwr(szTemp);
		if( strstr(szTemp,Buffer) ) return true;
		else return false;
	}
	return true;
}

bool havePowerSource(PCHAR ID, long B=0, long E=NUM_INV_SLOTS) {
	for( int iSlot=B; iSlot < E; iSlot++ ) {
		if( PCONTENTS cSlot=GetCharInfo2()->InventoryArray[iSlot] ) {
			if( (atoi(ID) && atoi(ID) == cSlot->Item->ItemNumber ) || !stricmp(ID,cSlot->Item->Name) ) {
				if( !cSlot->Power ) return false;
				return true;
			} else if( cSlot->Item->Type == ITEMTYPE_PACK ) {
				for( int iPack=0; iPack < cSlot->Item->Slots; iPack++ ) {
					if( PCONTENTS cPack=cSlot->Contents[iPack]) {
						if( (atoi(ID) && atoi(ID) == cPack->Item->ItemNumber ) || !stricmp(ID,cPack->Item->Name) ) {
							if( !cPack->Power ) return false;
							return true;
						}
					}
				}
			}
		}
	}
	return false;
}

void Exchange() {
	if( !cPowerSource[0] || GetCharInfo()->pSpawn->CastingData.SpellID != -1 || GetCharInfo2()->Cursor ||
		(pActiveCorpse && pLootWnd) || (pActiveMerchant && pMerchantWnd) ) return;

	if( PCONTENTS cSlot=GetCharInfo2()->InventoryArray[iPowerSourceSlot] ) {
		if( cSlot->Power ) return;
	}
	else if( !havePowerSource(cPowerSource) ) return;

	typedef VOID (__cdecl *ExchangeCALL) (PCHAR);
	char zOutput[MAX_STRING];

	if( atoi(cPowerSource) ) sprintf(zOutput,"%d powersource",atoi(cPowerSource));
	else sprintf(zOutput,"\"%s\" powersource",cPowerSource);

	PMQPLUGIN pLook=pPlugins;
	while( pLook && strnicmp(pLook->szFilename,"MQ2Exchange",11) ) pLook=pLook->pNext;
	if( pLook && pLook->fpVersion>1.1500 )
		if( ExchangeCALL Request=(ExchangeCALL)GetProcAddress(pLook->hModule,"doExchange") )
			Request(zOutput);
}

void Unequip() {
	if( !cPowerSource[0] || GetCharInfo()->pSpawn->CastingData.SpellID != -1 || GetCharInfo2()->Cursor ||
		(pActiveCorpse && pLootWnd) || (pActiveMerchant && pMerchantWnd) ) return;
	
	if(PCONTENTS cSlot=GetCharInfo2()->InventoryArray[iPowerSourceSlot]) {
		if( !cSlot->Power ) WriteChatf("[MQ2TribSave]:: [MQ2TribSave]:: Unequip \ar%s\ax.  Power depleted. New power source with power must be first to be equiped", cSlot->Item->Name);

		typedef VOID (__cdecl *UnequipCALL) (PCHAR);
		PMQPLUGIN pLook=pPlugins;
		while( pLook && strnicmp(pLook->szFilename,"MQ2Exchange",11) ) pLook=pLook->pNext;
		if( pLook && pLook->fpVersion>1.1500 )
		if( UnequipCALL Request=(UnequipCALL)GetProcAddress(pLook->hModule,"doUnequip") )
			Request("powersource");
	}
}

BOOL Open(PCHAR WindowName) {
  PCSIDLWND pWnd=(PCSIDLWND)FindMQ2Window(WindowName);
  return (!pWnd)?false:(BOOL)pWnd->Show;
}

void ClickTributeButton() {
	bool bWasOpen=true;
	if(!Open("tributebenefitwnd")) {
		DoMappable((PSPAWNINFO)pCharSpawn,"toggle_tributebenefitwin");
		bWasOpen=false;
	}
	SendWndClick("tributebenefitwnd","DowngradeButton","leftmouseup"); 
	if(!bWasOpen) DoMappable((PSPAWNINFO)pCharSpawn,"toggle_tributebenefitwin");
} 

VOID setStatus(bool status,bool statusChange,PCHAR szMessage) {
	static bool tripon = false;
	if( status ) {
		if( !tripon || !*pTributeActive ) {
			if( !combatZone() && bTribAutoActive && !*pTributeActive ) {
				tripon = true;
			} else if( !*pTributeActive ) {
				tripon = true;
				ClickTributeButton();
				setAction();
				if( szMessage[0] ) WriteChatf(szMessage);
			} else {
				tripon = true;
			}
		}
	} else if( !status ) {
		if( GetCharInfo()->TributeTimer < TRIB_OFF_TIME ) {
			ClickTributeButton();			
			if( szMessage[0] ) WriteChatf(szMessage);
		}
		tripon = false;
	}
	if( statusChange ) bTribStatus = tripon;
}

/*
//	Ingame commands:
//	/tribsave [#] [on|off] [auto|*noauto] [mouse|*nomouse] [move|*nomove] [status]
*/
VOID MQTribSaveCommand(PSPAWNINFO pSpawn,PCHAR szLine)
{
	bool turnOn = false;
	bool idleChanged = false;
	bool bSaveChanges = false;

	char zParm[MAX_STRING];
	char zTemp[MAX_STRING];
	long iParm=0;
	do {
		GetArg(zParm,szLine,++iParm);
		if( zParm[0]==0 ) { break;
		} else if( !strnicmp(zParm,"on",2) ) {
			turnOn = true;
		} else if( !strnicmp(zParm,"off",3) ) {
			setStatus(false,true,"[MQ2TribSave]:: Will turn off when less than 10 seconds");
			return;
		} else if( !strnicmp(zParm,"auto",4) ) {
			bTribAutoActive = true;
		} else if( !strnicmp(zParm,"noauto",6) ) {
			bTribAutoActive = false;
		} else if( !strnicmp(zParm,"mouse",5) ) {
			bCheckMouse = true;
		} else if( !strnicmp(zParm,"nomouse",7) ) {
			bCheckMouse = false;
		} else if( !strnicmp(zParm,"casting",7) ) {
			bCheckCasting = true;
		} else if( !strnicmp(zParm,"nocasting",9) ) {
			bCheckCasting = false;
		} else if( !strnicmp(zParm,"attack",6) ) {
			bCheckAttacking = true;
		} else if( !strnicmp(zParm,"noattack",8) ) {
			bCheckAttacking = false;
		} else if( !strnicmp(zParm,"move",4) ) {
			bCheckMove = true;
		} else if( !strnicmp(zParm,"nomove",6) ) {
			bCheckMove = false;
		} else if( !strnicmp(zParm,"save",4) ) {
			bSaveChanges = true;
		} else if( !strnicmp(zParm,"load",4) ) {
			ReadWindowINI(true);
			status(true);
			return;
		} else if( !strnicmp(zParm,"status",6) ) {
			status(true);
			return;
		} else if( !strnicmp(zParm,"-ps|",4) ) {
			GetArg(cPowerSource,zParm,2,FALSE,FALSE,FALSE,'|');

			GetArg(zTemp,zParm,3,FALSE,FALSE,FALSE,'|');
			if ( atoi(zTemp) ) {
				iPowerSourceSeconds = atoi(zTemp);
				idleChanged = true;
			}
		} else if( atoi(zParm) ) {
			iTribIdelTime = atoi(zParm);
			if( iTribIdelTime < 0 ) iTribIdelTime = 0;
			idleChanged = true;
		}
	} while(true);

	if( turnOn ) {
		if( !bTribAutoActive ) {
			setAction();
			setStatus(true,true,"");
		}
		status();
	} else if( idleChanged ) {
		status();
	}
	if( bSaveChanges ) WriteWindowINI();
}

/*
//	Get Setting's to Inifile MQ2TribSave.ini
//	In the Section [Settings.<ServerName>.<PlayerName>]
*/
bool ReadWindowINI(bool announceLoading) {
	static bool ReadOnce = false;
	if( ReadOnce && !announceLoading ) return false;
	DebugSpewAlways("MQ2CastTimer::ReadWindowINI()");
	if( GetCharInfo() && GetCharInfo()->pSpawn && ( !ReadOnce || announceLoading ) ) {
		if( announceLoading ) WriteChatf("[MQ2TribSave]:: \agLoading...\ax");
		char szSettingINISection[MAX_STRING];
		sprintf(szSettingINISection,"Settings.%s.%s",EQADDR_SERVERNAME,GetCharInfo()->pSpawn->Name);

		GetPrivateProfileString(szSettingINISection,"TribCombatZones","|",cTribCombatZones,MAX_STRING,INIFileName);
		GetPrivateProfileString(szSettingINISection,"TribNoCombatZones","|",cTribNoCombatZones,MAX_STRING,INIFileName);

		iTribIdelTime = GetPrivateProfileInt(szSettingINISection,"TribIdelTime",   5,INIFileName);
		bTribStatus = 0x00000001 & GetPrivateProfileInt(szSettingINISection,"TribStatus",   0,INIFileName);
		bCheckMouse = 0x00000001 & GetPrivateProfileInt(szSettingINISection,"CheckMouse",   0,INIFileName);
		bCheckMove = 0x00000001 & GetPrivateProfileInt(szSettingINISection,"CheckMove",   0,INIFileName);

		bTribAutoActive = 0x00000001 & GetPrivateProfileInt(szSettingINISection,"TribAuto",   0,INIFileName);

		GetPrivateProfileString(szSettingINISection,"PowerSource","",cPowerSource,MAX_STRING,INIFileName);
		iPowerSourceSeconds = GetPrivateProfileInt(szSettingINISection,"PowerSourceIdelTime",   0,INIFileName);

		bCheckCasting = 0x00000001 & GetPrivateProfileInt(szSettingINISection,"CheckCasting",   bCheckCasting,INIFileName);
		bCheckCastingDetrimental = 0x00000001 & GetPrivateProfileInt(szSettingINISection,"CheckCastingDetrimental",   bCheckCastingDetrimental,INIFileName);

		bCheckAttacking = 0x00000001 & GetPrivateProfileInt(szSettingINISection,"CheckAttacking",   bCheckAttacking,INIFileName);
//		bCheckGotHit = 0x00000001 & GetPrivateProfileInt(szSettingINISection,"CheckGotHit",   0,INIFileName);
		ReadOnce = true;
		return true;
	}
	ReadOnce = false;
	return false;
}

/*
//	Saves Setting's to Inifile MQ2TribSave.ini
//	In the Section [Settings.<ServerName>.<PlayerName>]
*/
VOID WriteWindowINI() {
	DebugSpewAlways("MQ2CastTimer::WriteWindowINI()");

	if( gbInZone && GetCharInfo() && GetCharInfo()->pSpawn ) {
		WriteChatf("[MQ2TribSave]:: \agSaving...\ax");
		char szSettingINISection[MAX_STRING];
		sprintf(szSettingINISection,"Settings.%s.%s",EQADDR_SERVERNAME,GetCharInfo()->pSpawn->Name);

		WritePrivateProfileString(szSettingINISection,"TribCombatZones",cTribCombatZones,INIFileName);
		WritePrivateProfileString(szSettingINISection,"TribNoCombatZones",cTribNoCombatZones,INIFileName);

		WritePrivateProfileString(szSettingINISection,"TribIdelTime",   itoa(iTribIdelTime,   Buffer,10),INIFileName);

		WritePrivateProfileString(szSettingINISection,"TribStatus",   itoa(bTribStatus,   Buffer,10),INIFileName);
		WritePrivateProfileString(szSettingINISection,"CheckMouse",   itoa(bCheckMouse,   Buffer,10),INIFileName);
		WritePrivateProfileString(szSettingINISection,"CheckMove",   itoa(bCheckMove,   Buffer,10),INIFileName);

		WritePrivateProfileString(szSettingINISection,"TribAuto",   itoa(bTribAutoActive,   Buffer,10),INIFileName);

		WritePrivateProfileString(szSettingINISection,"PowerSource",   cPowerSource,INIFileName);
		WritePrivateProfileString(szSettingINISection,"PowerSourceIdelTime",   itoa(iPowerSourceSeconds,   Buffer,10),INIFileName);

		WritePrivateProfileString(szSettingINISection,"CheckCasting",   itoa(bCheckCasting,   Buffer,10),INIFileName);
		WritePrivateProfileString(szSettingINISection,"CheckCastingDetrimental",   itoa(bCheckCastingDetrimental,   Buffer,10),INIFileName);
		WritePrivateProfileString(szSettingINISection,"CheckAttacking",   itoa(bCheckAttacking,   Buffer,10),INIFileName);
//		WritePrivateProfileString(szSettingINISection,"CheckGotHit",   itoa(bCheckGotHit,   Buffer,10),INIFileName);
	}
}

PLUGIN_API VOID InitializePlugin(VOID)
{
	DebugSpewAlways("Initializing MQ2TribSave");

	AddCommand("/tribsave",MQTribSaveCommand);
	lastActive = 0;

	for( int i = 0; szItemSlot[i]; i++ ) {
		if( !strnicmp(szItemSlot[i],"powersource",11) ) iPowerSourceSlot = i;
	}
	ReadWindowINI();
}


PLUGIN_API VOID ShutdownPlugin(VOID)
{
	DebugSpewAlways("Shutting down MQ2TribSave");
	RemoveCommand("/tribsave");
}

PLUGIN_API VOID OnPulse(VOID)
{
	if( !gbInZone || !GetCharInfo() || !GetCharInfo()->pSpawn ) return;
	bool bInavtive = true;

	ReadWindowINI();

	if( bTribStatus && bTribAutoActive && !*pTributeActive && combatZone() && ((bCheckCasting && isCastingSpell()) || (bCheckAttacking && *EQADDR_ATTACK)) ) {
		if( bOneShotOn ) {
			setStatus(true,true,"[MQ2TribSave]:: Reactivating");
			bOneShotOn = false;
		}
	} else {
		bOneShotOn = true;
	}

	if( bCheckMouse && (iOldMouseX != ((PMOUSEINFO)EQADDR_MOUSE)->X || iOldMouseY != ((PMOUSEINFO)EQADDR_MOUSE)->Y) ) {
		bInavtive = false;
	} else if( bCheckMove && (fOldLocX != (GetCharInfo()->pSpawn->X) || fOldLocY != (GetCharInfo()->pSpawn->Y)) ) {
		bInavtive = false;
	} else if( bCheckCasting && isCastingSpell() ) {
		bInavtive = false;
	}  else if( bCheckAttacking && *EQADDR_ATTACK ) {
		bInavtive = false;
	}

	if ( !bInavtive ) setAction();
	time_t now = time(NULL);

	if( bTribStatus && (iTribIdelTime > 0 || iPowerSourceSeconds) ) {
		PCONTENTS cSlot=GetCharInfo2()->InventoryArray[iPowerSourceSlot];
		if(cSlot && !cSlot->Power ) Unequip();
		else if( iPowerSourceSeconds) {
			if( now <= (lastActive + iPowerSourceSeconds) && combatZone() ) Exchange();
			else Unequip();
		} else if( now <= (lastActive + (iTribIdelTime * 60)) && combatZone() ) Exchange();
		else Unequip();
	}

	//if less than 10 secs left on this round, initiate checks
	if( GetCharInfo()->TributeTimer < TRIB_OFF_TIME ) {
		if( bOneShotOff ) {
			if( !bTribStatus && iTribIdelTime ) {
				setStatus(false,false,"[MQ2TribSave]:: Turned off, less than 10 seconds");
				bOneShotOff = false;
			} else if( !combatZone() ) {
				setStatus(false,false,bTribAutoActive?"[MQ2TribSave]:: Turned off, Non combat zone, Wating to reactivate":"[MQ2TribSave]:: Turned off, Non combat zone");
				bOneShotOff = false;
			} else if( bInavtive && iTribIdelTime ) {
				if( now > (lastActive + (iTribIdelTime * 60)) ) {
					setStatus(false,false,bTribAutoActive?"[MQ2TribSave]:: Turned off, Because you were idle, Wating to reactivate":"[MQ2TribSave]:: Turned off, Because you were idle");
					bOneShotOff = false;
				}
			}
		}
	} else {
		bOneShotOff = true;
	}
}

PLUGIN_API VOID SetGameState(DWORD GameState) {
	DebugSpewAlways("MQ2TribSave::SetGameState()");
	if( gGameState==GAMESTATE_CHARSELECT ) ReadWindowINI(true);
}